package com.cdu.eduPanda.project.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cdu.eduPanda.project.common.convention.exception.ClientException;
import com.cdu.eduPanda.project.common.convention.exception.ServiceException;
import com.cdu.eduPanda.project.config.JWTProperties;
import com.cdu.eduPanda.project.dao.entity.UserDO;
import com.cdu.eduPanda.project.dao.mapper.UserMapper;
import com.cdu.eduPanda.project.dto.req.UserLoginReqDTO;
import com.cdu.eduPanda.project.dto.req.UserRegisterReqDTO;
import com.cdu.eduPanda.project.dto.resp.UserLoginRespDTO;
import com.cdu.eduPanda.project.service.UserService;
import com.cdu.eduPanda.project.utils.JWTUtil;
import com.cdu.eduPanda.project.utils.MailMsgUtil;
import jakarta.mail.MessagingException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.cdu.eduPanda.project.common.constant.RedisCacheConstant.USER_LOGIN_KEY;
import static com.cdu.eduPanda.project.common.constant.RedisCacheConstant.USER_REGISTER_KEY;
import static com.cdu.eduPanda.project.common.convention.errorcode.BaseErrorCode.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {
    private final JWTProperties jwtProperties;
    private final StringRedisTemplate stringRedisTemplate;
    private final MailMsgUtil mailMsg;

    @Override
    public void getCaptcha(String email) {
        try {
            boolean isSend = mailMsg.mail(email);
        } catch (MessagingException e) {
            throw new ServiceException(USER_REGISTER_EMAIL_ERROR);
        }
    }

    @Override
    public void register(UserRegisterReqDTO requestParam) {
        String email = requestParam.getEmail();
        String captcha = stringRedisTemplate.opsForValue().get(USER_REGISTER_KEY + email);
        if(StrUtil.isBlank(captcha)){
            throw new ClientException(USER_REGISTER_EMAIL_CODE_OVERDUE);
        }
        if(!StrUtil.equals(captcha,requestParam.getCaptcha())){
            throw new ClientException(USER_REGISTER_EMAIL_CODE_ERROR);
        }
        UserDO userDO = UserDO.builder()
                .username(email)
                .password(MD5.create().digestHex(requestParam.getPassword()))
                .mail(email)
                .build();
        try {
            baseMapper.insert(userDO);
        } catch (Exception e) {
            throw new ServiceException("用户注册数据库插入失败");
        }
    }

    @Override
    public UserLoginRespDTO login(UserLoginReqDTO requestParam) {
        LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class)
                .eq(UserDO::getUsername, requestParam.getUsername());
        UserDO userDO = baseMapper.selectOne(queryWrapper);
        if (userDO == null) {
            throw new ClientException(USER_LOGIN_ERROR);
        }
        String pwd = MD5.create().digestHex(requestParam.getPassword());
        if (!StrUtil.equals(userDO.getPassword(), pwd)) {
            throw new ClientException(USER_LOGIN_ERROR);
        }
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", userDO.getId());
        claims.put("username", userDO.getUsername());
        String token = JWTUtil.createJWT(jwtProperties.getSecretKey(), jwtProperties.getTtl(), claims);
        stringRedisTemplate.opsForValue().set(USER_LOGIN_KEY + requestParam.getUsername(), token, 60L, TimeUnit.MINUTES);
        return UserLoginRespDTO.builder()
                .id(userDO.getId().toString())
                .username(userDO.getUsername())
                .token(token)
                .build();
    }

    @Override
    public Boolean checkLogin(String username) {
        return stringRedisTemplate.opsForValue().get(USER_LOGIN_KEY + username) != null;
    }

    @Override
    public void logout(String username) {
        if (checkLogin(username)) {
            stringRedisTemplate.delete(USER_LOGIN_KEY + username);
            return;
        }
        throw new ClientException(USER_ISNOT_LOGIN);
    }

}
